package com.basker.pisces.springcloud.feign.hystrix;

import java.lang.reflect.Method;
import java.util.stream.Stream;

import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

import com.basker.pisces.service.annotation.ServiceConsume;
import com.basker.pisces.service.annotation.ServiceConsume.IsolationStrategy;
import com.basker.pisces.springcloud.feign.FeignClientBeanProcessor;
import com.basker.pisces.springcloud.feign.FeignClientFactoryBeanAccessor;

/**
 * 读取在feignclient上关于hystrix的注解属性
 *
 * @author hangwen
 */
public class FeignHystrixAnnotationProptiesProcessor implements FeignClientBeanProcessor {

    private HystrixCodingPropertySource hystrixCodingPropertySource;

    public FeignHystrixAnnotationProptiesProcessor(HystrixCodingPropertySource hystrixCodingPropertySource) {
        this.hystrixCodingPropertySource = hystrixCodingPropertySource;
    }

    @Override
    public void processFeignClientBean(Object feignClientFactoryBean, ConfigurableListableBeanFactory beanFactory) {
        if (feignClientFactoryBean == null) {
            return;
        }

        // 获取当前的client类型，遍历其所有方法
        Class<?> targetType = (Class<?>) FeignClientFactoryBeanAccessor.getFieldValue(feignClientFactoryBean, "type");
        Stream.of(targetType.getMethods()).forEach(m -> readCommandProperties(targetType, m));
    }

    private void readCommandProperties(Class<?> targetType, Method method) {
        ServiceConsume serviceConsume = method.getAnnotation(ServiceConsume.class);
        if (serviceConsume == null) {
            return;
        }

        // 设置隔离模式
        IsolationStrategy isolationStrategy = serviceConsume.IsolationStrategy();
        if (!isolationStrategy.equals(IsolationStrategy.DEFAULT)) {
            this.hystrixCodingPropertySource.setCommandIsolationStrategy(targetType, method, isolationStrategy);
        }

        // 设置超时
        int timeoutMills = serviceConsume.timeoutMills();

        // 对于信号量模式，关闭熔断超时
        if (isolationStrategy.equals(IsolationStrategy.SEMAPHORE)) {
            timeoutMills = -1;
            this.hystrixCodingPropertySource.setCommandTimeoutEnable(targetType, method, false);

            // 设置信号量最大并发数
            int semaphoreMaxConcurrentRequests = serviceConsume.semaphoreMaxConcurrentRequests();
            if (semaphoreMaxConcurrentRequests > 0) {
                this.hystrixCodingPropertySource.setCommandSemaphoreMaxConcurrentRequests(targetType, method,
                        semaphoreMaxConcurrentRequests);
            }
        }

        if (timeoutMills > 0) {
            this.hystrixCodingPropertySource.setCommandTimeoutMills(targetType, method, timeoutMills);
        }

    }

}
